#include "websocketserver.h"
#include <iostream>


static bool isConnEixsted(const std::vector<const struct mg_connection *> &vtConns, const struct mg_connection *conn)
{
    bool bRet = false;
    for (size_t i = 0, size = vtConns.size(); i < size; ++i) {
        if (conn == vtConns[i]) {
            bRet = true;
            break;
        }
    }

    return bRet;
}

static void eraseConn(const struct mg_connection *conn, std::vector<const struct mg_connection *> &vtConns)
{
    for (auto iter = vtConns.begin(); iter != vtConns.end(); ++iter) {
        if (conn == *iter) {
            iter = vtConns.erase(iter);
            break;
        }
    }

    return;
}

static void sendWsTextData(const std::string &strData, const struct mg_connection *conn)
{
    if (strData.empty() || !conn) {
        std::cerr << ">>> strData is empty() or pConn is nullptr." << std::endl;
        return;
    }

    // 注：需要确保strData是UTF-8格式的内容，否则接收数据端可能报错，导致连接断开
    int iRet = mg_websocket_write((struct mg_connection *)conn, MG_WEBSOCKET_OPCODE_TEXT, strData.data(), strData.length());
    if (0 >= iRet) {
        std::cerr << ">>> websocket send text data ret: " << iRet << "." << std::endl;
    }

    return;
}

static void sendWsBinaryData(const char *pData, size_t iDataLen, const struct mg_connection *conn)
{
    if (!pData || !conn) {
        std::cerr << ">>> pData or pConn is nullptr." << std::endl;
        return;
    }

    // 注：这里不校验传输数据的类型，按二进制流进行传输
    int iRet = mg_websocket_write((struct mg_connection *)conn, MG_WEBSOCKET_OPCODE_BINARY, pData, iDataLen);
    if (0 >= iRet) {
        std::cerr << ">>> websocket send binary data ret: " << iRet << "." << std::endl;
    }

    return;
}

#if 0
WebsocketBaseHandler::WebsocketBaseHandler()
{

}
#endif

WebsocketBaseHandler::~WebsocketBaseHandler()
{
}

void WebsocketBaseHandler::setUrl(std::string strUrl)
{
    m_strUrl = strUrl;
    return;
}

std::string WebsocketBaseHandler::getUrl() const
{
    return m_strUrl;
}

void WebsocketBaseHandler::setPfnCBDealData(std::function<void(const std::string &, void *, void *)> pfnCBDealData, void *pContext)
{
    m_pfnCBDealData = pfnCBDealData;
    m_pContext = pContext;
    return;
}

size_t WebsocketBaseHandler::getConnectionSize()
{
    std::lock_guard<std::mutex> guard(m_mt4Conns);
    return m_vt4Conns.size();
}

bool WebsocketBaseHandler::handleConnection(CivetServer *server, const struct mg_connection *conn)
{
    (void)server;

    m_mt4Conns.lock();
    if (isConnEixsted(m_vt4Conns, conn)) {
        std::cerr << ">>> url " << m_strUrl << " connection is existed, please close first." << std::endl;
    } else {
        m_vt4Conns.emplace_back(conn);
        //std::cout << ">>> url " << m_strUrl << " is connected, the connection size: " << m_vt4Conns.size() << "." << std::endl;
    }
    m_mt4Conns.unlock();

    return true;
}

void WebsocketBaseHandler::handleClose(CivetServer *server, const struct mg_connection *conn)
{
    (void)server;

    m_mt4Conns.lock();
    if (isConnEixsted(m_vt4Conns, conn)) {
        eraseConn(conn, m_vt4Conns);
        //std::cout << ">>> url " << m_strUrl << " is closed, the connection size: " << m_vt4Conns.size() << "." << std::endl;
    } else {
        std::cerr << ">>> url " << m_strUrl << " connection is not existed, error." << std::endl;
    }
    m_mt4Conns.unlock();

    return;
}

bool WebsocketBaseHandler::handleData(CivetServer *server, struct mg_connection *conn, int bits, char *data, size_t data_len)
{
    (void)server;
    //(void)conn;
    (void)bits;


    if (data && 0 < data_len) {
        std::string strData(data, data_len);

        // TEST RSP
        // sendWsTextData("welcome!", conn);

        if (m_pfnCBDealData) {
            m_pfnCBDealData(strData, m_pContext, conn);
        }
    } else {
        std::cerr << ">>> url " << m_strUrl << " recv data pointer is nullptr or len is < 0" << std::endl;
    }

    return true;
}

void WebsocketBaseHandler::sendData(const char *pData, size_t iDataLen)
{
    std::vector<const struct mg_connection *> vt4Conns;
    if (m_mt4Conns.try_lock()){
        vt4Conns = m_vt4Conns;
        m_mt4Conns.unlock();
    } else {
        // 没有获取到锁，直接返回，避免接口阻塞
        return;
    }

    for (size_t i = 0, size = vt4Conns.size(); i < size; ++i) {
        sendWsBinaryData(pData, iDataLen, vt4Conns[i]);
    }

    return;
}

void WebsocketBaseHandler::sendData(const char *pData, size_t iDataLen, void *pConn)
{
    sendWsBinaryData(pData, iDataLen, (const struct mg_connection *)pConn);
    return;
}

void WebsocketBaseHandler::sendData(const std::string &strData)
{
    std::vector<const struct mg_connection *> vt4Conns;
    if (m_mt4Conns.try_lock()) {
        vt4Conns = m_vt4Conns;
        m_mt4Conns.unlock();
    } else {
        // 没有获取到锁，直接返回，避免接口阻塞
        return;
    }

    for (size_t i = 0, size = vt4Conns.size(); i < size; ++i) {
        sendWsTextData(strData, vt4Conns[i]);
    }

    return;
}

void WebsocketBaseHandler::sendData(const std::string &strData, void *pConn)
{
    sendWsTextData(strData, (const struct mg_connection *)pConn);
    return;
}

Example1WebsocketHandler::Example1WebsocketHandler()
{
    setUrl("/v1/example1");
}

Example1WebsocketHandler::~Example1WebsocketHandler()
{

}

Example2WebsocketHandler::Example2WebsocketHandler()
{
    setUrl("/v1/example2");
}

Example2WebsocketHandler::~Example2WebsocketHandler()
{

}

